﻿using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using IcicleFramework.GameServices;
using IcicleFramework.Renderables;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Newtonsoft.Json;

namespace IcicleFramework.Components.Renderable
{
    public class RenderComponent : BaseComponent, IRenderComponent
    {
        protected bool visible;

        public override bool Active
        {
            get { return Visible; }
            set { Visible = value; }
        }
        
        [JsonProperty]
        protected Dictionary<string, IRenderable> renderables;

        public int NumRenderables
        {
            get { return renderables.Count; }
        }

        public IRenderable GetRenderable(string name)
        {
            return renderables.ContainsKey(name) ? renderables[name] : null;
        }

        public IRenderable GetRenderable(int index)
        {
            return renderables.Count > index ? renderables.Values.ToArray()[index] : null;
        }

        public void SetShading(Color shading)
        {
            foreach (IRenderable renderable in renderables.Values)
                renderable.ColorChannel = shading;
        }

        public void SetScale(float scale)
        {
            foreach (IRenderable renderable in renderables.Values)
                renderable.Scale = scale;
        }

        public void SetLayer(float layer)
        {
            foreach (IRenderable renderable in renderables.Values)
                renderable.Layer = layer;
        }
        
        public RenderComponent()
        {
            renderables = new Dictionary<string, IRenderable>();
            visible = true;
        }

        public RenderComponent(RenderComponent old)
            : base(old)
        {
            renderables = new Dictionary<string, IRenderable>();

            foreach (var renderableKeyValue in old.renderables)
            {
                var newRenderable = renderableKeyValue.Value.DeepClone();
                newRenderable.Parent = this;
                renderables.Add(renderableKeyValue.Key, newRenderable);
            }
        }

        public bool AddRenderable(IRenderable renderable, string name)
        {
            if (!renderables.ContainsKey(name))
            {
                renderables.Add(name, renderable);
                return true;
            }

            return false;
        }

        public override void Update(GameTime gameTime)
        {
            foreach (IRenderable renderable in renderables.Values)
                renderable.Update(gameTime);
        }

        public override void Initialize()
        {
            foreach (IRenderable renderable in renderables.Values)
                renderable.Initialize();

            base.Initialize();
        }

        public virtual bool Visible
        {
            get { return visible; }
            set
            {
                if (value != visible)
                {
                    foreach (IRenderable renderable in renderables.Values)
                        renderable.Visible = value;

                    visible = value;
                }
            }
        }

        public virtual void Draw(SpriteBatch spriteBatch)
        {
            if (Visible)
            {
                foreach (IRenderable renderable in renderables.Values)
                    renderable.Draw(spriteBatch);
            }
        }

        public virtual void Load(ContentManager content)
        {
            foreach (IRenderable renderable in renderables.Values)
                renderable.Load(content);
        }


        public override void Deserialize(XElement element)
        {
            //Read in all of our renderables.
            if (element.Element("renderables") != null)
            {
                RenderableFactory factory = (RenderableFactory)GameServiceManager.GetService(typeof(RenderableFactory));

                if (factory != null)
                    renderables = factory.GenerateRenderables(element.Element("renderables"), this);
            }
        }

        public override IBaseComponent DeepClone()
        {
            return new RenderComponent(this);
        }

        public override void Dispose()
        {
            foreach (var renderable in renderables.Values)
                renderable.Dispose();

            base.Dispose();
        }

        
    }
}
